
#include "Screen.h"
#include "../ScriptApi.h"

using namespace System::Windows::Forms;
namespace GTA
{
	Screen::Screen()
	{
		Log::Debug("Screen constructor");
		Forms = gcnew System::Collections::Generic::List<GTAForm^>();
		GTA::Events::KeyUp::Handler +=  gcnew System::EventHandler<GTA::Events::KeyEventArgs^>(Screen::OnKeyUp);
		GTA::Events::RunTick::Handler +=  gcnew System::EventHandler<EventArgs^>(Screen::RunTick);
		GTA::Events::CleanUp::Handler +=  gcnew System::EventHandler<GTA::Events::CleanUpEventArgs^>(Screen::CleanUp);
	}
	
	void Screen::RunTick(Object^ sender, EventArgs^ args)
	{
		DrawForms();
		DrawMouse();
	}

	void Screen::CleanUp(Object^ sender, GTA::Events::CleanUpEventArgs^ args)
	{

	}

#pragma region Forms
	void Screen::DrawForms()
	{
		for each (GTAForm^ form in Forms)
		{
			if (form == nullptr) continue;
			if (!form->Visible) continue;
			DrawForm(form);
		}
	}

	void Screen::DrawForm(GTAForm^ form)
	{ // draws the form onto game screen. TODO: D3D drawing
		//System::Drawing::Bitmap^ frmbmp = gcnew System::Drawing::Bitmap(form->Width,form->Height);
		//form->DrawToBitmap(frmbmp, System::Drawing::Rectangle(0,0,form->Width,form->Height));
		if (form == nullptr)
			return;
		float x1, y1, x2, y2;
		u32 resx, resy;
		ScriptApi::GetScreenResolution(&resx,&resy);
		x1 = safe_cast<float>((safe_cast<float>(safe_cast<float>(form->Left) + (safe_cast<float>(form->Width) / 2.0F)) / safe_cast<float>(resx)) * 1.0F);
		y1 = safe_cast<float>((safe_cast<float>(safe_cast<float>(form->Top) + (safe_cast<float>(form->Height) / 2.0F)) / safe_cast<float>(resy)) * 1.0F);
		x2 = safe_cast<float>((safe_cast<float>(safe_cast<float>(form->Width)) / safe_cast<float>(resx)) * 1.0F);
		y2 = safe_cast<float>((safe_cast<float>(safe_cast<float>(form->Height)) / safe_cast<float>(resy)) * 1.0F);
		System::Byte r, g, b, a;
		r = form->BackColor.R;
		g = form->BackColor.G;
		b = form->BackColor.B;
		a = form->BackColor.A;
		if (a >= 255)
			a = 170;
		ScriptApi::DrawRect(x1,y1,x2,y2,r,g,b,a);
		for each (Control^ ctrl in form->Controls)
		{
			DrawFormControl(form,ctrl);
		}

	}

	void Screen::DrawFormControl(Control^ parent, Control^ ctrl)
	{ // draws the controls on the form on gamescreen
		float x1, y1, x2, y2;
		u32 resx, resy;
		ScriptApi::GetScreenResolution(&resx,&resy);
		x1 = ((safe_cast<float>(parent->Left) + (safe_cast<float>(ctrl->Left) + (safe_cast<float>(ctrl->Width) / 2.0F))) / safe_cast<float>(resx)) * 1.0F;
		y1 = ((safe_cast<float>(parent->Top) + (safe_cast<float>(ctrl->Top) + (safe_cast<float>(ctrl->Height) / 2.0F))) / safe_cast<float>(resy)) * 1.0F;
		x2 = (safe_cast<float>(ctrl->Width) / safe_cast<float>(resx)) * 1.0F;
		y2 = (safe_cast<float>(ctrl->Height) / safe_cast<float>(resy)) * 1.0F;
		System::Byte r, g, b, a;
		r = ctrl->BackColor.R;
		g = ctrl->BackColor.G;
		b = ctrl->BackColor.B;
		a = ctrl->BackColor.A;
		if (a >= 255)
			a = 150;

		// --TEXT--
		float texscalex, texscaley;
		texscalex = safe_cast<float>(ctrl->Font->Size) / (float)(resx/20);
		texscaley = texscalex;
		float texx1, texy1;
		texx1 = x1 - (((safe_cast<float>(ctrl->Width) / 2.0F) / safe_cast<float>(resx)) * 1.0F); //lhs of control
		texy1 = y1 - (((safe_cast<float>(ctrl->Height) / 2.0F) / safe_cast<float>(resx)) * 1.0F); //top of control
		texx1 += (safe_cast<float>(ctrl->Font->Size)*safe_cast<float>(ctrl->Width/4))/40000.0F;
		//texx1 += (((safe_cast<float>(ctrl->Width) / 20.0F) / safe_cast<float>(resx)) * 1.0F); // middle of control
		System::Byte tr, tg, tb, ta;
		tr = ctrl->ForeColor.R;
		tg = ctrl->ForeColor.G;
		tb = ctrl->ForeColor.B;
		ta = ctrl->ForeColor.A;
		ScriptApi::SetTextColour(tr, tg, tb, ta);
		ScriptApi::SetTextScale(texscalex, texscaley);
		ScriptApi::SetTextDropshadow(false, 0, 0, 0, 0);
		// --/TEXT--

		if (ctrl->GetType()->Equals(Button::typeid))
		{
			Button^ button = safe_cast<Button^>(ctrl);
			ScriptApi::DrawRect(x1, y1, x2 + 0.001F, y2 + 0.001F, safe_cast<System::Byte>(r + 10), safe_cast<System::Byte>(g + 10), safe_cast<System::Byte>(b + 10), 64); //outside
			ScriptApi::DrawRect(x1,y1,x2,y2,r,g,b,a);
			if (button->Text != "")
			{
				ScriptApi::DisplayTextWithLiteralString(texx1, texy1, "STRING", button->Text);
			}
		}
		else if (ctrl->GetType()->Equals(Label::typeid))
		{
			Label^ lbl = safe_cast<Label^>(ctrl);
			if (lbl->Text != "")
			{
				texx1 -= texscalex/10.0F;
				ScriptApi::DisplayTextWithLiteralString(texx1, texy1, "STRING", lbl->Text);
			}
		}
		if (ctrl->GetType()->Equals(CheckBox::typeid))
		{
			CheckBox^ chk = safe_cast<CheckBox^>(ctrl);
			x2 = 0.02F;
			y2 = 0.02F;
			ScriptApi::DrawRect(x1 - 0.04F, y1-0.01F, x2, y2, r, g, b, a);
			if (!chk->Checked)
				ScriptApi::DrawRect(x1 - 0.04F, y1 - 0.01F, x2 - 0.005F, y2 - 0.005F, 0, 0, 0, a);
			else
				ScriptApi::DrawRect(x1 - (0.04F+0.01F), y1 - (0.01F+0.01F), x2 - 0.02F, y2 - 0.02F, 0, 0, 0, a);
			ScriptApi::DisplayTextWithLiteralString(texx1 + 0.03F, texy1, "STRING", chk->Text);
		}
	}

	void Screen::AddForm(GTAForm^ form)
	{
		if (form == nullptr) Log::Debug("Form add null");
		for each (GTAForm^ f in Forms)
		{
			if (f == nullptr) continue;
			if (f == form) return;
		}
		Forms->Add(form);
	}

	void Screen::RemoveForm(GTAForm^ form)
	{
		int foundid = -1;
		for (int i=0;i<Forms->Count;i++)
		{
			if (Forms[i] == form) foundid = i;
		}
		if (foundid >= 0) Forms->Remove(form);
	}

	GTAForm^ Screen::GetFormFromScreenXY(float x, float y)
	{
		u32 resx, resy;
		ScriptApi::GetScreenResolution(&resx,&resy);
		int px, py;
		px = safe_cast<u32>((x / 1.0F) * safe_cast<float>(resx));
		py = safe_cast<u32>((y / 1.0F) * safe_cast<float>(resy));

		for each (GTAForm^ frm in Forms)
		{
			if (frm == nullptr) continue;
			if (((px > frm->Left) && (px < frm->Left + frm->Width)) && ((py > frm->Top) && (py < frm->Top + frm->Height)))
				return frm;
		}
		return nullptr;
	}

	Control^ Screen::GetControlFromScreenXY(GTAForm^ form, float x, float y)
	{
		u32 resx, resy;
		ScriptApi::GetScreenResolution(&resx, &resy);
		int px, py;
		px = safe_cast<u32>((x / 1.0F) * safe_cast<float>(resx));
		py = safe_cast<u32>((y / 1.0F) * safe_cast<float>(resy));

		for each (Control^ ctrl in form->Controls)
		{
			if (ctrl == nullptr)
				continue;
			if ((px > (form->Left + ctrl->Left)) && (px < (form->Left + (ctrl->Left + ctrl->Width))))
			{ // x ok
				if ((py > (form->Top + ctrl->Top)) && (py < (form->Top + (ctrl->Top + ctrl->Height))))
				{ // y ok
					return ctrl;
				}
			}
		}
		return nullptr;
	}
#pragma endregion DrawForms(); DrawForm(); DrawFormControl(); AddForm(); RemoveForm(); GetFormFromScreenXY(); GetControlFromScreenXY();

#pragma region Mouse
	void Screen::DrawMouse()
	{ // draw the mouse onscreen
	            
        bool showmouse = false;
        for each (GTAForm^ form in Forms)
        {
            if (form == nullptr) continue;
			if (!form->Visible) continue;
			if (form->UseMouse) {showmouse = true; break; };
        }
        if (!showmouse) return; // no forms requesting mouse
		float mx, my;
		ScriptApi::GetMousePosition(&mx, &my);
		if (!ScriptApi::HasStreamedTxdLoaded("network"))
		{
			ScriptApi::RequestStreamedTxd("network", true);
			if (!ScriptApi::HasStreamedTxdLoaded("network"))
			{
				Log::Warning("World::DrawMouse: Texture not loaded!");
				return;
			}
		}
		GTA::Texture^ mtext = GTA::ScriptApi::GetTextureFromStreamedTxd("network", "MOUSECURSOR");

		ScriptApi::DrawSprite(mtext, mx + 0.020F, my + 0.020F, 0.040F, 0.057F, 0.0F, 255, 255, 255, 255);
		//ScriptApi.MarkStreamedTxdAsNoLongerNeeded("network");
	}

	void Screen::OnKeyUp(System::Object^ sender, GTA::Events::KeyEventArgs^ args)
	{
		CheckMouseClick(safe_cast<short>(args->KeyValue));
	}

	void Screen::CheckMouseClick(short KeyCode)
	{
		float mx, my;
		ScriptApi::GetMousePosition(&mx, &my);
		if (KeyCode == safe_cast<short>(Keys::LButton))
		{
			//Log::Debug("Screen: CheckMouseClick LMB!!!!!!!!!!");
			GTAForm^ foundfrm = GetFormFromScreenXY(mx,my);

			if (foundfrm != nullptr)
			{
				if ((foundfrm->Visible) && (foundfrm->UseMouse))
				{
					//Log::Debug("Clicked in form: " + foundfrm->Name);
					Control^ foundctrl = GetControlFromScreenXY(foundfrm, mx, my);
					if (foundctrl != nullptr)
					{
						//Log::Debug("Clicked in control: " + foundctrl->Name);
						if (foundctrl->GetType()->Equals(Button::typeid))
						{
							//Log::Debug("its a button");
							Button^ btn = safe_cast<Button^>(foundctrl);

							array<System::Object^>^ args = gcnew array<System::Object^>(1);
							args[0] = EventArgs::Empty;
							System::Reflection::MethodInfo^ m = Button::typeid->GetMethod("OnClick", System::Reflection::BindingFlags::NonPublic | System::Reflection::BindingFlags::Instance);
							m->Invoke(btn, args);
						}

						if (foundctrl->GetType()->Equals(CheckBox::typeid))
						{
							//Log::Debug("its a checkbox");
							CheckBox^ chk = safe_cast<CheckBox^>(foundctrl);
							chk->Checked = !chk->Checked;
	//                                
	//                                object[] args = new object[1];
	//                                args[0] = EventArgs.Empty;
	//                                System.Reflection.MethodInfo m = typeof(CheckBox).GetMethod("OnCheckedChanged", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
	//                                m.Invoke(chk, args);
	//                                 * 
						}
					}
				}
			}
		}
	}
#pragma endregion DrawMouse(), CheckMouseClick()


	void Screen::PrintString(String^ text,u32 timeMS)
	{
		ScriptApi::PrintStringWithLiteralStringNow("STRING",text,timeMS,true);
	}
};